package com.ruoyi.common.utils.rtf;

import java.util.ArrayList;
import java.util.List;

/**
 * 在将富文本指令解析成中文时，借助了ISO8859-1编码格式，该编码格式是单字节编码格式，不会丢失字节。
 * 后来发现该编码没有对00-FF全覆盖，部分字节没有定义,这就导致转成ISO8859-1之后，部分字节会丢失。
 *
 * 本类处理该问题，在遇到这种字节时，转成特定的内容，然后在转中文之前，再转回来。
 * 具体处理办法：
 * 1 根据ISO8859-1字符集确定特殊字符范围：00-1F，7F-9F,一共65个。
 * 2 遇到这些字节时，先添加前缀，然后将字节+24，形成”前缀+转移后字节“的形式比如，遇到0x01,就转成前缀+0x31。
 * （这个方法一方面为了规范，另一方面，根据ISO8859-1标准，加24之后，刚好等于下移三行，不超FF，也能落到有效字节范围内）
 * 3 转换成中文之前，将”前缀+转移后字节“恢复成原字节。
 */
public class ISO8859ISpecialByte {
    //特殊字符，来自ISO8859-1字符集
    private static String[] specialByteStrsA = {
            "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
            "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
            "7f",
            "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
            "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f"
    };
    //字节转换之后的内容，这个在ISO8859-1中都有定义
    private static String[] specialByteStrsB = {
            "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
            "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
            "af",
            "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
            "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf"
    };

    //字节前缀，来自rtf标准格式
    private static String sep = "\\\\'";
    //转成iso8859-1之前，添加前缀，搞复杂一些避免后面去除前缀时，误去除
    private static String conversionSuxBeforeToISO = sep + "fb" + sep + "fc" + sep + "fd" + sep + "fe" + sep + "ff";
    //byte内容的前缀，和 conversionSuxBeforeToISO 保持一致
    private static byte[] inverseSuxBeforeToZh = {(byte) 0xfb, (byte) 0xfc, (byte) 0xfd, (byte) 0xfe, (byte) 0xff};

    /**
     *
     * @param rtfStr rtf标准字符串
     * @return 转移后字符串，已经转义了iso8859-1未定义的字节
     */
    public static String conversionStr(String rtfStr) {
        if (rtfStr == null) {
            return null;
        }
        for (int i = 0; i < specialByteStrsA.length; i++) {
            String a = sep + specialByteStrsA[i];
            String b = conversionSuxBeforeToISO + sep + specialByteStrsB[i];
            rtfStr = rtfStr.replaceAll(a, b);
        }
        return rtfStr;
    }

    /**
     *
     * @param data
     * @return
     */
    public static byte[] inverseStr(byte[] data) {
        if (data == null || data.length <= inverseSuxBeforeToZh.length) {
            return data;
        }

        List<Byte> result = new ArrayList<Byte>();
        int i = 0;
        boolean flag = true;
        while (flag) {
            if (i > data.length - 1 - inverseSuxBeforeToZh.length) {
                break;
            }

            if (data[i] == inverseSuxBeforeToZh[0]) {
                //开始匹配conversionStr转义之后的内容
                boolean find = true;
                for (int j = 1; j < inverseSuxBeforeToZh.length - 1; j++) {
                    if (data[i + j] != inverseSuxBeforeToZh[j]) {
                        find = false;
                        break;
                    }
                }
                if (find) {
                    boolean match = false;
                    //匹配成功，准备恢复字节
                    for (int j = 0; j < specialByteStrsA.length; j++) {
                        if (specialByteStrsB[j].equalsIgnoreCase(byteToHexStr(data[i + inverseSuxBeforeToZh.length]))) {
                            int val = Integer.valueOf(specialByteStrsA[j],  16);
                            result.add((byte) val);
                            match = true;
                            break;
                        }
                    }
                    if (match) {
                        i++;
                        i = i + inverseSuxBeforeToZh.length;
                    } else {
                        //匹配上了前缀，但是最后的字节不满足要求，按照没匹配上继续
                        result.add(data[i]);
                        i++;
                    }
                } else {
                    result.add(data[i]);
                    i++;
                }
            } else {
                result.add(data[i]);
                i++;
            }
        }
        //处理最后几个字节
        if (data[data.length - 1 - inverseSuxBeforeToZh.length] != inverseSuxBeforeToZh[0]) {
            for (int j = inverseSuxBeforeToZh.length; j >= 1 ; j--) {
                result.add(data[data.length - j]);
            }
        }
        if (result == null || result.size() == 0) {
            return new byte[]{};
        } else {
            byte[] resultBytes = new byte[result.size()];
            for (int j = 0; j < result.size(); j++) {
                resultBytes[j] = result.get(j);
            }
            return resultBytes;
        }
    }

    public static String byteToHexStr(byte c) {
        int byteValue = c & 0XFF;
        if (c == 0) {
            return "00";
        } else if (c < 16 && c > 0) {
            return "0" + Integer.toHexString(byteValue);
        }
        return Integer.toHexString(byteValue);

    };
}
